﻿using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Text.RegularExpressions;

namespace GrainManage.Data.Access
{
    public class InOutParameterBuilder : IParameterBuilder
    {
        public class ParameterInfo
        {
            public string Name { get; set; }
            public string Direction { get; set; }
        }

        private static Dictionary<string, ParameterInfo[]> Parameters = new Dictionary<string, ParameterInfo[]>();

        private static object lockObj = new object();

        private GrainManage.Data.Provider.IProvider provider;

        public InOutParameterBuilder(GrainManage.Data.Provider.IProvider provider)
        {
            this.provider = provider;
        }

        public void AddParameters(System.Data.Common.DbCommand cmd, object[] parameterValues)
        {
            var procName = cmd.CommandText;
            if (!Parameters.ContainsKey(procName))
            {
                string fullParas = null;
                using (var con = provider.Connection)
                {
                    var scmd = provider.GetCommand("ProcInfo_GetParaByName", con);
                    scmd.Parameters.Add(provider.GetDbParameter("xProcName", procName));
                    scmd.Parameters.Add(provider.GetDbParameter("xCanWriteBack", true));
                    con.Open();
                    fullParas = scmd.ExecuteScalar() as string;
                    fullParas = string.IsNullOrEmpty(fullParas) ? string.Empty : fullParas.Trim(' ');
                }

                ParameterInfo[] splitParaInfo = new ParameterInfo[0];
                if (fullParas.Length > 0)
                {
                    fullParas = Regex.Replace(fullParas, @"[\s]+", string.Empty);//去除所有的空白
                    string[] splitParameters = fullParas.Split(';');
                    splitParaInfo = new ParameterInfo[splitParameters.Length];
                    for (int i = 0; i < splitParameters.Length; i++)
                    {
                        var singlePara = splitParameters[i].Split(',');
                        var paraInfo = new ParameterInfo();
                        paraInfo.Name = singlePara[0].Split('.')[1];
                        paraInfo.Direction = singlePara[1];
                        splitParaInfo[i] = paraInfo;
                    }
                }

                lock (lockObj)
                {
                    if (!Parameters.ContainsKey(procName))
                    {
                        Parameters[procName] = splitParaInfo;
                    }
                }
            }

            var parameterInfoList = Parameters[procName];
            if (parameterInfoList.Length != parameterValues.Length)
            {
                throw new System.Exception("the number of parameters is not right.");
            }

            for (int i = 0; i < parameterInfoList.Length; i++)
            {
                ParameterDirection direction = parameterInfoList[i].Direction.Equals("IN") ? ParameterDirection.Input : ParameterDirection.Output;
                cmd.Parameters.Add(provider.GetDbParameter(parameterInfoList[i].Name, parameterValues[i], direction));
            }
        }

        public static void SetOutput(DbCommand cmd, object[] parameterValues)
        {
            for (int i = 0; i < cmd.Parameters.Count; i++)
            {
                if (cmd.Parameters[i].Direction == ParameterDirection.Output)
                {
                    parameterValues[i] = cmd.Parameters[i].Value;
                }
            }
        }
    }
}
